﻿using Aliyun.OSS;
using Aliyun.OSS.Common;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Common.Aliyun
{
    /// <summary>
    /// 文件对象上传
    /// </summary>
    public class OSSObjectUploader
    {
        private readonly IConfiguration configuration;
        private readonly ConfigHelper configHelper;
        /// <summary>
        /// 强制使用外网入口
        /// </summary>
        private readonly bool forceToInternetEndpoint;
        /// <summary>
        /// OSS对象上传
        /// </summary>
        /// <param name="configuration"></param>
        /// <param name="forceToInternetEndpoint">强制使用外网入口</param>
        public OSSObjectUploader(IConfiguration configuration, bool forceToInternetEndpoint = false)
        {
            this.configuration = configuration;
            this.configHelper = new ConfigHelper(this.configuration);
            this.forceToInternetEndpoint = forceToInternetEndpoint;
        }
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="bucket"></param>
        /// <param name="objectName"></param>
        /// <param name="binaryData"></param>
        /// <param name="metadata"></param>
        /// <returns></returns>
        public FuncResult<string> Execute(string bucket, string objectName, byte[] binaryData, Dictionary<string, string> metadata = null)
        {
            var credential = STSCredential.GetSTSCredentail(bucket, this.configuration);
            if (credential == null)
            {
                return null;
            }
            var endpoint = this.configHelper.GetBucketEndPoint(bucket);
            bool cname = false;
            string bucketEndpoint = endpoint.InternalEndpoint;//默认使用内网入口上传
            if (forceToInternetEndpoint)
            {
                cname = !string.IsNullOrEmpty(endpoint.CName);
                bucketEndpoint = string.IsNullOrEmpty(endpoint.CName) ? endpoint.EndPoint : endpoint.CName;
            }
            var clientConfiguration = new ClientConfiguration();
            clientConfiguration.IsCname = cname;
            clientConfiguration.Protocol = Protocol.Https;
            // 创建OssClient实例。
            var client = new OssClient(bucketEndpoint, credential.AccessKeyId, credential.AccessKeySecret, credential.SecurityToken, clientConfiguration);
            ObjectMetadata mdata = null;
            if (metadata != null)
            {
                mdata = new ObjectMetadata();
                foreach (var kv in metadata)
                {
                    mdata.UserMetadata.Add(kv.Key, kv.Value);
                }
            }
            try
            {
                MemoryStream requestContent = new MemoryStream(binaryData);
                // 上传文件。
                var result = client.PutObject(bucket, objectName, requestContent, mdata);
                int statusCode = (int)result.HttpStatusCode;
                if (statusCode >= 200 && statusCode < 300)
                {
                    return FuncResult.Success<string>(string.Concat("https://", bucketEndpoint, "/", objectName));
                }
                return FuncResult.Fail<string>($"上传文件失败，响应码:{statusCode}{result.HttpStatusCode}");
            }
            catch (OssException ex)
            {
                DiagnosticHelper.Write("OSSObjectUpload.Execute", $"failed with error code: {ex.ErrorCode}", ex);
                return FuncResult.Fail<string>(ex.Message);
            }
            catch (Exception ex)
            {
                DiagnosticHelper.Write("OSSObjectUpload.Execute", "上传文件出现异常", ex);
                return FuncResult.Fail<string>(ex.Message);
            }
        }
    }
}
